﻿using System;
using System.Collections.Generic;
using System.Linq.Expressions;

using Fuse8.DomainFramework.Domain;
using Fuse8.DomainFramework.Common;
using Fuse8.DomainFramework.Common.Locator;

namespace Fuse8.DomainFramework.BusinessService
{
    /// <summary>
    /// 
    /// </summary>
    /// <typeparam name="TEntity"></typeparam>
    /// <typeparam name="TKey"></typeparam>
    public sealed class BusinessServiceFacade<TEntity, TKey> : IEntityBusinessService<TEntity, TKey>
        where TEntity : class, IEntityObject<TKey>, new()
        where TKey : IComparable<TKey>, IEquatable<TKey> 
    {
        private IEntityBusinessService<TEntity, TKey> _service;

        /// <summary>
        /// 
        /// </summary>
        internal IEntityBusinessService<TEntity, TKey> InnerService
        {
            get 
			{
            	return _service ?? (_service = DependencyServiceLocator.Current.GetInstance<IEntityBusinessService<TEntity, TKey>>());
            }
        }

        /// <summary>
        /// 
        /// </summary>
        public BusinessServiceFacade()
        {
            if (!DependencyServiceLocator.Current.IsDefaultServiceRegistered<IEntityBusinessService<TEntity, TKey>>())
            {
                IEntityBusinessService<TEntity, TKey> defaultService = new DefaultBusinessService<TEntity, TKey>();
                DependencyServiceLocator.Current.SetDefaultService<IEntityBusinessService<TEntity, TKey>>(defaultService);
            }
        }

        #region IEntityBusinessService<T> Members

        /// <summary>
        /// 
        /// </summary>
        public TEntity Entity
        {
            get
            {
                return InnerService.Entity;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="entityObject"></param>
        public void Add(TEntity entityObject)
        {
            Guard.ArgumentNotNull(entityObject, "entityObject");

            InnerService.Add(entityObject);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="entityObject"></param>
        public void Save(TEntity entityObject)
        {
            Guard.ArgumentNotNull(entityObject, "entityObject");

            InnerService.Save(entityObject);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="entityObject"></param>
        public void Remove(TEntity entityObject)
        {
            Guard.ArgumentNotNull(entityObject, "entityObject");

            InnerService.Remove(entityObject);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="id"></param>
        public void Remove(TKey id)
        {
            if (!id.Equals(default(TKey)))
            {
                InnerService.Remove(id);
            }
        }

        /// <summary>
        /// 
        /// </summary>        
        /// <param name="id"></param>
        /// <returns></returns>
        public TEntity FindOne(TKey id)
        {
            return !id.Equals(default(TKey)) ? InnerService.FindOne(id) : default(TEntity);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="expression"></param>
        /// <returns></returns>
        public TEntity FindOne(Expression<Func<TEntity, bool>> expression)
        {
            Guard.ArgumentNotNull(expression, "expression");

            return InnerService.FindOne(expression);
        }
		/// <summary>
		/// 
		/// </summary>
		/// <param name="expression"></param>
		/// <param name="selectExpression"></param>
		/// <returns></returns>
    	public TEntity FindOne(Expression<Func<TEntity, bool>> expression, Expression<Func<TEntity, object>> selectExpression)
    	{
			Guard.ArgumentNotNull(expression, "expression");
			Guard.ArgumentNotNull(selectExpression, "expression");

			return InnerService.FindOne(expression, selectExpression);
		}

    	/// <summary>
        /// 
        /// </summary>
        /// <param name="expression"></param>
        /// <returns></returns>
        public IEnumerable<TEntity> Find(Expression<Func<TEntity, bool>> expression)
        {
            Guard.ArgumentNotNull(expression, "expression");

            return InnerService.Find(expression);
        }

		/// <summary>
		/// 
		/// </summary>
		/// <param name="expression"></param>
		/// <param name="selectExpression"></param>
		/// <returns></returns>
    	public IEnumerable<TEntity> Find(Expression<Func<TEntity, bool>> expression, Expression<Func<TEntity, object>> selectExpression)
    	{
			Guard.ArgumentNotNull(expression, "expression");
			Guard.ArgumentNotNull(selectExpression, "expression");

			return InnerService.Find(expression, selectExpression);
		}

    	/// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public IEnumerable<TEntity> FindAll()
        {
            return InnerService.FindAll();
        }

		/// <summary>
		/// 
		/// </summary>
		/// <param name="selectExpression"></param>
		/// <returns></returns>
    	public IEnumerable<TEntity> FindAll(Expression<Func<TEntity, object>> selectExpression)
    	{
			Guard.ArgumentNotNull(selectExpression, "expression");

			return InnerService.FindAll(selectExpression);
		}

    	/// <summary>
        /// 
        /// </summary>
        /// <param name="command"></param>
        /// <returns></returns>
        public TEntity FindOne(IEntityCommand<TEntity> command)
        {
            Guard.ArgumentNotNull(command, "command");

            return InnerService.FindOne(command);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="command"></param>
        /// <param name="clearDependency"></param>
        /// <returns></returns>
        public TEntity FindOne(IEntityCommand<TEntity> command, bool clearDependency)
        {
            Guard.ArgumentNotNull(command, "command");

            return InnerService.FindOne(command, clearDependency);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="command"></param>
        /// <returns></returns>
        public IEnumerable<TEntity> Find(IEntityCommand<TEntity> command)
        {
            Guard.ArgumentNotNull(command, "command");

            return InnerService.Find(command);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="command"></param>
        /// <param name="clearDependency"></param>
        /// <returns></returns>
        public IEnumerable<TEntity> Find(IEntityCommand<TEntity> command, bool clearDependency)
        {
            Guard.ArgumentNotNull(command, "command");

            return InnerService.Find(command, clearDependency);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="command"></param>
        public void Execute(IEntityCommand<TEntity> command)
        {
            InnerService.Execute(command);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="command"></param>
        /// <returns></returns>
        [Obsolete("Use FindOne method instead")]
        public TEntity FindOneByCommand(IEntityCommand<TEntity> command)
        {
            return FindOne(command);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="command"></param>
        /// <param name="clearDependency"></param>
        /// <returns></returns>
        [Obsolete("Use FindOne method instead")]
        public TEntity FindOneByCommand(IEntityCommand<TEntity> command, bool clearDependency)
        {
            return FindOne(command, clearDependency);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="command"></param>
        /// <returns></returns>
        [Obsolete("Use Find method instead")]
        public IEnumerable<TEntity> FindByCommand(IEntityCommand<TEntity> command)
        {
            return Find(command);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="command"></param>
        /// <param name="clearDependency"></param>
        /// <returns></returns>
        [Obsolete("Use Find method instead")]
        public IEnumerable<TEntity> FindByCommand(IEntityCommand<TEntity> command, bool clearDependency)
        {
            return Find(command, clearDependency);
        }

        #endregion       
    }
}
